using System;
using System.Collections.Generic;
using System.Text;
using Logic.Exceptions;
using Data;
using Data.Probabilities;
namespace Logic.Sequential
{
    public class Sequential
    {
        private int maxL;
        private int k;
        private int n;
        private double epsilon;
        private Isequential tempPartition;
       // private SeqData tempPartition;
        private Cell[] bestPartition;
        private double sumOfbestPartion;

        #region constructors
        //public Sequential(Isequential seqData)
        //{   
        //    Console.WriteLine("\nClass Sequential: Running default constractor\n");
        //    this.maxL = 4;
        //    this.n = 2;
        //    Epsilon = 0.7;
        //    this.k = 2;
        //    this.sumOfbestPartion = double.MaxValue;
        //    this.tempPartition = new SeqData(this.k);
        //    this.bestPartition = null;
        //}

        public Sequential(int k, int maxL, int n, double epsilon, ProbabilityData probData)
        {
            K = k;
            MaxL = maxL;
            N = n;
            Epsilon = epsilon;
            this.tempPartition = new SeqData(this.k, probData);
            this.bestPartition = null;
            this.sumOfbestPartion = double.MaxValue;
        }
        #endregion

        #region getters and seters
        public int MaxL
        {
            get
            {
                return this.maxL;
            }
            set
            {
                try
                {
                    if (value > 0)
                        this.maxL = value;
                    else
                        throw new NumberOutOfRangeException("Error: MaxL must be positive");
                }
                catch (NumberOutOfRangeException e)
                {
                    Console.WriteLine("{0}", e.Message);
                }
            }
        }

        public int N
        {
            get
            {
                return this.n;
            }
            set
            {
                try
                {
                    if (value > 0)
                        this.n = value;
                    else
                        throw new NumberOutOfRangeException("Error: N must be a positive number");
                }
                catch (NumberOutOfRangeException e)
                {
                    Console.WriteLine("{0}", e.Message);
                }
            }
        }

        public int K
        {
            get
            {
                return this.k;
            }
            set
            {
                try
                {
                    if (value > 1)
                        this.k = value;
                    else
                        throw new NumberOutOfRangeException("Error: number of clusters must be 2 or more");
                }
                catch (NumberOutOfRangeException e)
                {
                    Console.WriteLine("{0}", e.Message);
                }
            }
        }

        public Cell[] BestPartition
        {
            get
            {
                return this.bestPartition;
            }
        }

        public double Epsilon
        {
            get
            {
                return this.epsilon;
            }
            set
            {
                try
                {
                    if (value > 0 && value <= 1)
                        this.epsilon = value;
                    else
                        throw new NumberOutOfRangeException("Error: Epsilon must be between (0,1]");
                }
                catch (NumberOutOfRangeException e)
                {
                    Console.WriteLine("{0}", e.Message);
                }
            }
        }
        #endregion

        #region Methood
        public void runSequential()
        {
            for (int i = 0; i < this.n; i++)
            {
                int numberOfGenomes = this.tempPartition.makePartition();
                //Create the array only one time !!!
                if (this.bestPartition == null)
                {
                    this.bestPartition = new Cell[numberOfGenomes];
                    for (int k = 0; k < numberOfGenomes; k++)
                        this.bestPartition[k] = new Cell();
                }
                int c = 0;
                int C = 0;
                bool done = false;

                while (!done)
                {
                    for (int j = 0; j < numberOfGenomes; j++)
                    {
                        this.tempPartition.removedGenome(j);
                        this.tempPartition.computeMinimum();
                        this.tempPartition.merge();
                        if (!(this.tempPartition.isSameGroup()))
                            c = c + 1;
                    }
                    C = C + 1;
                    if ((C >= this.maxL) || (c < this.epsilon * numberOfGenomes))
                        done = true;
                }
             //   this.tempPartition.calculateSumOfMinimalLost();
                if (this.tempPartition.SumOfMinimalLose < this.sumOfbestPartion)
                {
                    (this.tempPartition.TheGroups).CopyTo(this.bestPartition, 0);
                    this.sumOfbestPartion = this.tempPartition.SumOfMinimalLose;
                }
            }
        }
        #endregion
    }
}
